import { RPCClient } from "@alicloud/pop-core";
import lodash from "lodash";
import { success, successResponse, errorResponse } from "../utils/result.js";
import {
  Video,
  User,
  Comment,
  VideoLike,
  Follow,
  VideoCollect,
} from "../models/index.js";
import mongoose from "mongoose";
import { videoHotInc, getVideoHots } from "../models/videoHot.js";
import { aliyunConfig } from "../config/config.default.js";

// 检查视频是否存在
const checkVideoExists = async (vId) => {
  return await Video.findById(vId);
};
// 验证vId是否有效
const checkvIdValid = (vId) => {
  if (!mongoose.Types.ObjectId.isValid(vId)) {
    throw new Error("无效的视频ID");
  }
};
// 初始化VOD客户端
function initVodClient() {
  return new RPCClient({
    accessKeyId: aliyunConfig.accessKeyId,
    accessKeySecret: aliyunConfig.accessKeySecret,
    endpoint: `http://vod.${aliyunConfig.vodRegion}.aliyuncs.com`,
    apiVersion: "2017-03-21",
  });
}
/**
 * 获取视频上传凭证
 */
export const getUploadAuth = async (req, res, next) => {
  console.log(req.body);

  const { title, description, fileName } = req.body;

  let client = initVodClient();
  try {
    const vod = await client.request("CreateUploadVideo", {
      Title: title,
      Description: description,
      FileName: fileName,
    });
    res.status(200).json(successResponse(vod));
  } catch (err) {
    next(err);
  }
};

/**
 * 刷新上传凭证
 */
export const refresghUploadAuth = async (req, res, next) => {
  const { vId } = req.body;
  let client = initVodClient();
  try {
    const response = await client.request("RefreshUploadVideo", {
      videoId: vId,
    });
    res.status(200).json(successResponse(response));
  } catch (err) {
    next(err);
  }
};
/**
 * 上传视频
 */
export const createVideo = async (req, res, next) => {
  const body = req.body;
  body.user = req.user.id;
  try {
    const video = new Video(body);
    await video.save();
    res.status(200).json(success("上传成功"));
  } catch (err) {
    next(err);
  }
};
// 获取视频播放凭证
export const getPlayAuth = async (req, res, next) => {
  let client = initVodClient();
  const vId = req.params.vId;
  if (!vId) {
    return res.status(400).json(errorResponse("视频ID不能为空"));
  }
  try {
    const response = await client.request("GetVideoPlayAuth", {
      VideoId: vId,
    });
    res.status(200).json(successResponse(response));
  } catch (err) {
    next(err);
  }
};

/**
 * 获取vod视频播放信息
 */
export const getPlayInfo = async (req, res, next) => {
  let client = initVodClient();
  const vodId = req.params.vodId;
  if (!vodId) {
    return res.status(400).json(errorResponse("视频ID不能为空"));
  }
  try {
    const response = await client.request("GetPlayInfo", {
      VideoId: vodId,
    });
    res.status(200).json(successResponse(response));
  } catch (err) {
    next(err);
  }
};
/**
 * 视频列表
 */
export const list = async (req, res, next) => {
  let { pageNum = 1, pageSize = 10 } = req.query;
  const skip = (pageNum - 1) * pageSize;
  try {
    const videos = await Video.find({})
      .skip(skip)
      .limit(pageSize)
      .sort({ createTime: -1 })
      .populate({
        path: "user",
        select: "_id username avatar",
      });
    const total = await Video.countDocuments();
    res.status(200).json(successResponse({ total, videos }));
  } catch (err) {
    next(err);
  }
};

/**
 * 视频推荐列表
 */
export const hots = async (req, res, next) => {
  const { num } = req.query;
  try {
    const hots = await getVideoHots(num);
    const videos = await Promise.all(
      Object.keys(hots).map(async (key) => {
        const video = await Video.findById(key);
        if (video) {
          return lodash.pick(video, [
            "_id",
            "title",
            "vodId",
            "cover",
            "likeCount",
          ]);
        }
        return null;
      })
    );

    res.status(200).json(successResponse({ videos }));
  } catch (err) {
    next(err);
  }
};

/**
 * 视频详情
 */
export const detail = async (req, res, next) => {
  const vId = req.params.vId;
  // 判断是否点赞
  let isLike = false;
  // 判断是否关注
  let isFollow = false;
  try {
    checkvIdValid(vId);
    const video = await Video.findById(vId).populate({
      path: "user",
      select: "_id username avatar",
    });
    if (!video) {
      return res.status(404).json(errorResponse("视频不存在"));
    }
    if (req.user) {
      const userId = req.user.id;
      // 同时查找点赞和关注记录
      const [videoLike, videoFollow] = await Promise.all([
        VideoLike.findOne({ user: userId, video: vId }),
        Follow.findOne({ user: userId, follow: video.user._id }),
      ]);
      isLike = !!videoLike;
      isFollow = !!videoFollow;
    }
    await Promise.all([
      Video.findByIdAndUpdate(vId, { $inc: { playCount: 1 } }),
    ]);

    await videoHotInc(vId, "watch");
    res.status(200).json(successResponse({ video, isLike, isFollow }));
  } catch (err) {
    next(err);
  }
};

/**
 * 删除视频
 */
export const remove = async (req, res, next) => {
  const vId = req.params.vId;
  try {
    checkvIdValid(vId);
    const video = await checkVideoExists(vId);
    if (!video) {
      return res.status(404).json(errorResponse("视频不存在"));
    }
    if (video.user.toString() !== req.user.id) {
      return res.status(403).json(errorResponse("当前用户不能删除该视频"));
    }
    try {
      await Promise.all([
        Video.findByIdAndDelete(vId),
        Comment.deleteMany({ video: vId }),
        VideoLike.deleteMany({ video: vId }),
      ]);
      res.status(200).json(success("删除成功"));
    } catch (err) {
      next(err);
    }
  } catch (err) {
    next(err);
  }
};

/**
 * 更新视频信息
 */
export const update = async (req, res, next) => {
  const vId = req.params.vId;
  const { title, description, cover } = req.body;
  try {
    checkvIdValid(vId);
    const video = await Video.findByIdAndUpdate(vId, {
      title,
      description,
      cover,
    });
    if (!video) {
      return res.status(404).json(errorResponse("视频不存在"));
    }
    res.status(200).json(success("更新成功"));
  } catch (err) {
    next(err);
  }
};
// 设置点赞记录和视频点赞数和用户点赞数
const setVideoLikeAndCount = async (isLike, userId, vId) => {
  // 首先更新视频和用户的点赞数
  await Promise.all([
    Video.findByIdAndUpdate(vId, { $inc: { likeCount: isLike ? 1 : -1 } }),
    User.findByIdAndUpdate(userId, { $inc: { likeCount: isLike ? 1 : -1 } }),
  ]);
  // 然后处理点赞记录
  if (!isLike) {
    await VideoLike.findOneAndDelete({ user: userId, video: vId });
  } else {
    await new VideoLike({ user: userId, video: vId }).save();
  }
};

/**
 * 视频点赞
 */
export const like = async (req, res, next) => {
  const { vId } = req.params;
  const userId = req.user.id;
  try {
    checkvIdValid(vId);
    const video = await checkVideoExists(vId);
    if (!video) {
      return res.status(404).json(errorResponse("视频不存在"));
    }
    const videoLike = await VideoLike.findOne({ user: userId, video: vId });
    if (!videoLike) {
      await setVideoLikeAndCount(true, userId, vId);
      await videoHotInc(vId, "like");
      return res.status(200).json(success("点赞成功"));
    } else {
      return res.status(400).json(errorResponse("当前视频已点赞"));
    }
  } catch (err) {
    next(err);
  }
};

/**
 * 视频取消点赞
 */
export const unlike = async (req, res, next) => {
  const { vId } = req.body;
  const userId = req.user.id;
  try {
    checkvIdValid(vId);
    const video = await checkVideoExists(vId);
    if (!video) {
      res.status(404).json(errorResponse("视频不存在"));
      return;
    }
    const videoLike = await VideoLike.findOne({ user: userId, video: vId });
    if (videoLike) {
      await setVideoLikeAndCount(false, userId, vId);
      res.status(200).json(success("取消成功"));
      return;
    } else {
      res.status(400).json(errorResponse("当前视频已未点赞"));
      return;
    }
  } catch (err) {
    next(err);
  }
};

// 设置收藏记录和视频点赞数和用户点赞数
const setVideoCollectAndCount = async (isCollect, userId, vId) => {
  // 处理视频收藏数
  await Promise.all([
    Video.findByIdAndUpdate(vId, {
      $inc: { collectCount: isCollect ? 1 : -1 },
    }),
  ]);
  // 然后处理收藏记录
  if (!isCollect) {
    await VideoCollect.findOneAndDelete({ user: userId, video: vId });
  } else {
    await new VideoCollect({ user: userId, video: vId }).save();
  }
};

/**
 * 视频收藏
 */
export const collect = async (req, res, next) => {
  const { vId } = req.body;
  const userId = req.user.id;
  try {
    checkvIdValid(vId);
    const video = await checkVideoExists(vId);
    if (!video) {
      return res.status(404).json(errorResponse("视频不存在"));
    }
    const videoCollect = await VideoCollect.findOne({
      user: userId,
      video: vId,
    });
    if (!videoCollect) {
      await setVideoCollectAndCount(true, userId, vId);
      await videoHotInc(vId, "collect");
      return res.status(200).json(success("收藏成功"));
    } else {
      return res.status(400).json(errorResponse("当前视频已收藏"));
    }
  } catch (err) {
    next(err);
  }
};

/**
 * 视频取消收藏
 */
export const uncollect = async (req, res, next) => {
  const { vId } = req.body;
  const userId = req.user.id;
  try {
    checkvIdValid(vId);
    const video = await checkVideoExists(vId);
    if (!video) {
      return res.status(404).json(errorResponse("视频不存在"));
    }
    const videoCollect = await VideoCollect.findOne({
      user: userId,
      video: vId,
    });
    if (videoCollect) {
      await setVideoCollectAndCount(false, userId, vId);
      return res.status(200).json(success("取消成功"));
    } else {
      return res.status(400).json(errorResponse("当前视频已未收藏"));
    }
  } catch (err) {
    next(err);
  }
};

/**
 * 视频评论
 */
export const comment = async (req, res, next) => {
  const { content, vId } = req.body;
  try {
    checkvIdValid(vId);
    const video = await checkVideoExists(vId);
    if (!video) {
      res.status(404).json(errorResponse("视频不存在"));
      return;
    }
    await Promise.all([
      new Comment({
        user: req.user.id,
        video: vId,
        content,
      }).save(),
      Video.findByIdAndUpdate(vId, { $inc: { commentCount: 1 } }),
    ]);
    await videoHotInc(vId, "comment");
    res.status(200).json(success("评论成功"));
  } catch (err) {
    next(err);
  }
};

/**
 * 视频评论列表
 */
export const comments = async (req, res, next) => {
  const vId = req.params.vId;
  const { pageNum = 1, pageSize = 10 } = req.query;
  const skip = (pageNum - 1) * pageSize;
  try {
    checkvIdValid(vId);
    const video = await checkVideoExists(vId);
    if (!video) {
      return res.status(404).json(errorResponse("视频不存在"));
    }
    const comments = await Comment.find({ video: vId })
      .skip(skip)
      .limit(pageSize)
      .sort({ createTime: -1, likeCount: -1 })
      .populate({
        path: "user",
        select: "_id username avatar",
      });
    res.status(200).json(successResponse(comments));
  } catch (err) {
    next(err);
  }
};
